package com.linkoog.devtools.raw_index.task;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.indexing.FileBasedIndexImpl;
import com.intellij.util.keyFMap.KeyFMap;
import com.linkoog.devtools.raw_index.PsiRawFileIndex;
import com.linkoog.devtools.raw_index.PsiRawFileIndexChangeListener;
import com.linkoog.devtools.utils.PsiClassUtils;

import java.util.List;

public class DeleteIndexTask implements Runnable{

    private static final Logger log = Logger.getInstance(DeleteIndexTask.class);


    private final Project project;
    private final PsiRawFileIndexChangeListener psiRawFileIndexChangeListener;

    private final VirtualFile virtualFile;
    private final Key<Long> cacheUpdateTimeKey;
    private final long fileUpdateTime;

    public DeleteIndexTask(Project project, PsiRawFileIndexChangeListener psiRawFileIndexChangeListener, VirtualFile virtualFile, Key<Long> cacheUpdateTimeKey, long fileUpdateTime) {
        this.project = project;
        this.psiRawFileIndexChangeListener = psiRawFileIndexChangeListener;
        this.virtualFile = virtualFile;
        this.cacheUpdateTimeKey = cacheUpdateTimeKey;
        this.fileUpdateTime = fileUpdateTime;
    }

    @Override
    public void run() {
        ApplicationManager.getApplication().invokeLater(() -> PsiDocumentManager.getInstance(project).commitAllDocuments());
        DumbService.getInstance(project).runReadActionInSmartMode(()->{
            if (! virtualFile.isValid()) return;

            long start = System.currentTimeMillis();

            if (! isPsiIndexReady(virtualFile)) return;
            //progressIndicator.setText("DevTools fileIndex waiting for Update index time: " + (System.currentTimeMillis() - start));

            deleteIndex();
            //KeyFMap map = psiRawFileIndexChangeListener.get();
            psiRawFileIndexChangeListener.putUserData(cacheUpdateTimeKey, null);
        });
    }

    /**
     *   virtualFile 文件内容变化，更新索引
     */
    private void deleteIndex(){
        final List<PsiRawFileIndex> list = PsiRawFileIndex.EXTENSION_POINT_NAME.getExtensions(project);
        if (list.isEmpty()){
            return;
        }

        long startTime = System.currentTimeMillis();
        for (PsiRawFileIndex psiRawFileIndex : list) {
            try {
                psiRawFileIndex.afterFileDelete(virtualFile);
            }catch (ProcessCanceledException ignored){

            } catch (Exception e){
                log.error("删除索引失败, psiRawFileIndex:  " + psiRawFileIndex.getClass() + "   , class:  " + virtualFile.getName(), e);
            }
        }
        log.info("Indexing [" + virtualFile.getName() + "] cost time: " + (System.currentTimeMillis() - startTime) + "ms");
    }



    private boolean isPsiIndexReady(VirtualFile virtualFile){
        FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance();
        if (!(fileBasedIndex instanceof FileBasedIndexImpl fileBasedIndexImpl)) return false;

        Document document = FileDocumentManager.getInstance().getCachedDocument(virtualFile);
        if (document == null) return false;

        boolean saved = !FileDocumentManager.getInstance().isDocumentUnsaved(document);
        if (!saved) return false;

        PsiFile psiFile =  PsiManagerEx.getInstanceEx(project).getFileManager().getCachedPsiFile(virtualFile);
        if (psiFile == null || !psiFile.isValid()) return false;

        //文件长度不一致，说明文件内容有变化
        if (psiFile.getTextLength() != document.getTextLength() || !fileBasedIndexImpl.isFileUpToDate(virtualFile)) {
            ApplicationManager.getApplication().invokeLater(() -> fileBasedIndexImpl.requestReindex(virtualFile));
            return false;
        }

        return true;
    }
}
